<?php

// comment this line out if on windows 9x or any other os not supporting flock()
define("WITH_FLOCK", 1);	

class morecache{

	var $expireafter;
	var $expiretype;
	var $filenames;
	var $searchvars;
	var $replacevars;
	var $activecaches = -1;
	var $cachepath = "./cached";


	function setexpiry($expireafter = 60){	
		$this->expireafter = $expireafter;
		if( is_int($expireafter) ){
			$this->expiretype = "sec";
		}else{
			$this->expiretype = "date";
		}
	}

	function morecache( $cachepath = "", $expireafter = 3600){
		if( $cachepath != "" ) $this->cachepath = $cachepath;
		else $this->cachepath = dirname(dirname(__FILE__))."/cache";
		$this->setexpiry($expireafter);
		$this->filenames = array();
		$this->searchvars = array();
		$this->replacevars = array();
		$this->activecaches = -1;
	}


	function makecachename($id){
		return $this->cachepath."/".md5($id).".cache";
	}

	function expirecache($cachename){
		$filename = $this->makecachename($cachename);
		@unlink($filename);
	}

	function cache($cachename, $expireafter = "", $search = array(), $replace=array()){
		if( !is_array($search) ) $search = array($search);
		$this->activecaches++;

		$this->filenames[$this->activecaches] = $this->makecachename($cachename);
		$this->searches[$this->activecaches] = &$search;
		$this->replaces[$this->activecaches] = &$replace;

		if( $expireafter == "" ) $expireafter = $this->expireafter;
		$this->setexpiry($expireafter);

		$update = 0;
		if( !file_exists($this->filenames[$this->activecaches]) ){
			$update = 1;
			$exist = 0;
		}else{
			$exist = 1;
			$updated = filemtime($this->filenames[$this->activecaches]);
		}

		if( $exist ==0 || $updated < ($this->expiretype == "sec" ? time() - $this->expireafter : strtotime($this->expireafter))){
			$update = 1;
		}

		if( $update){ 
			ob_start();
			return true;
		}else{
			if( count($this->searches[$this->activecaches]) == 0 ){
				$fp = $this->flock($this->filenames[$this->activecaches], "r");
				if(!@readfile( $this->filenames[$this->activecaches])) $this->error = "readfile failed for ".$this->filenames[$this->activecaches];
				$this->funlock($fp);
			}else{
				$f = join("", file($this->filenames[$this->activecaches]));
				echo str_replace($this->searches[$this->activecaches], $this->replaces[$this->activecaches], $f);
			}
			return false;
		}
	}

	function stop($returnbuffer = false, $showoutput = true){		// if returnbuffer is true, returns the contents of the cache to the calling script
		$this->cachecontents = ob_get_contents();
		$this->save();
		if( $showoutput == true && count( $this->searches[$this->activecaches]) != 0 ){
			ob_end_clean();
			echo str_replace($this->searches[$this->activecaches], $this->replaces[$this->activecaches], $this->cachecontents);
		}elseif( $showoutput == true ){
			ob_end_flush();
		}else{
			ob_end_clean();
		}
		$this->activecaches--;
		return ($showoutput == true ? $this->cachecontents : true);
	}

	function flock($filename, $mode){
		$fp = @fopen($filename, $mode = "r" ? "r" : "wb");
		if( defined(WITH_FLOCK) ) flock($fp, $mode="r" ? LOCK_SH : LOCK_EX);
		ignore_user_abort(true);
		return $fp;
	}

	function funlock($fp){
		if( $fp ){
			flock($fp, LOCK_UN);
			@fclose($fp);
		}
	}

	function save(){
		$fo = $this->flock($this->filenames[$this->activecaches], "w");
		if( $fo ){
			if( !@fwrite( $fo, $this->cachecontents)) $this->error = "Error writing to file ".$this->filenames[$this->activecaches];
			$this->funlock($fo);
		}else{
			$this->error = "Failed opening file ".$this->filenames[$this->activecaches]." for output.";
		}
	}

}

?>